/**
 * CodeLens functionality for ArenaNext
 * Provides code lens providers for functions and classes
 */

import { showNotification } from "./utils";

/**
 * Registers CodeLens provider for functions and classes
 * @param {Object} monacoController - The Monaco controller instance
 * @param {Function} chatRunner - Function to handle chat-related editor actions
 */
export function registerCodeLensProvider(monacoController, chatRunner) {
  const monaco = monacoController.monacoController.monaco;

  try {
    // 注册CodeLens提供器
    monaco.languages.registerCodeLensProvider("javascript", {
      provideCodeLenses: function (model) {
        try {
          return getDocumentSymbols(model, monaco)
            .then((symbols) => {
              if (!symbols || symbols.length === 0) {
                return { lenses: [], dispose: () => {} };
              }

              const codeLenses = [];

              function findSymbol(symbols) {
                for (const symbol of symbols) {
                  if (symbol.children && symbol.children.length > 0) {
                    findSymbol(symbol.children);
                  }

                  if (["Class", "Method", "Function"].includes(symbol.kind)) {
                    const range = {
                      startLineNumber: symbol.range.startLineNumber,
                      startColumn: 1,
                      endLineNumber: symbol.range.endLineNumber,
                      endColumn: model.getLineMaxColumn(
                        symbol.range.endLineNumber
                      ),
                    };

                    codeLenses.push({
                      range: range,
                      id: `codelen-${symbol.name}-${symbol.range.startLineNumber}`,
                      command: {
                        id: "editor.action.showCodeLensMenu",
                        title: `$(tools)  Chat吉PT`,
                        arguments: [model, range, symbol.name, symbol.kind],
                      },
                    });
                  }
                }
              }

              findSymbol(symbols);
              return { lenses: codeLenses, dispose: () => {} };
            })
            .catch((error) => {
              console.error("获取文档符号失败:", error);
              return { lenses: [], dispose: () => {} };
            });
        } catch (error) {
          console.error("CodeLens提供者错误:", error);
          return { lenses: [], dispose: () => {} };
        }
      },

      resolveCodeLens: function (model, codeLens) {
        try {
          return codeLens;
        } catch (error) {
          console.error("解析CodeLens错误:", error);
          return codeLens;
        }
      },
    });

    // 注册命令处理CodeLens菜单交互
    monaco.editor.registerCommand(
      "editor.action.showCodeLensMenu",
      function (_, model, range, symbolName, symbolKind) {
        try {
          // 选择整个代码块
          const editor = monaco.editor.getEditors()[0];
          editor.setSelection(range);

          // 获取代码内容
          let codeContent = "";
          for (let i = range.startLineNumber; i <= range.endLineNumber; i++) {
            codeContent += model.getLineContent(i) + "\n";
          }

          // 创建对话选项
          const dialogOptions = [
            { id: "analyze", label: "详细分析", type: 3 },
            { id: "optimize", label: "优化建议", type: 2 },
            { id: "debug", label: "修复错误", type: 1 },
            { id: "comment", label: "添加注释", type: 6 },
            { id: "refactor", label: "重构代码", type: 13 },
            { id: "copy", label: "复制代码", type: "copy" },
          ];

          // 显示自定义菜单
          showCodeLensMenu(
            dialogOptions,
            chatRunner,
            editor,
            range,
            monaco,
            codeContent
          );
        } catch (error) {
          console.error("显示CodeLens菜单失败:", error);
        }
      }
    );
  } catch (error) {
    console.error("注册CodeLens提供者失败:", error);
  }
}

/**
 * Shows the CodeLens menu with AI action options
 * @param {Array} options - The menu options to display
 * @param {Function} chatRunner - Function to handle chat actions
 * @param {Object} editor - The Monaco editor instance
 * @param {Object} range - The code range
 * @param {Object} monaco - The Monaco instance
 * @param {String} codeContent - The selected code content
 * @private
 */
function showCodeLensMenu(
  options,
  chatRunner,
  editor,
  range,
  monaco,
  codeContent = ""
) {
  // 创建菜单容器
  const menuDiv = document.createElement("div");
  menuDiv.className = "chat-jpt-code-menu";
  menuDiv.style.cssText = `
    position: fixed;
    background-color: #2d2d2d;
    border: 1px solid #444;
    border-radius: 6px;
    padding: 4px 0;
    box-shadow: 0 2px 8px rgba(0,0,0,0.5);
    z-index: 2000;
    font-size: 12px;
  `;

  // 根据鼠标位置或代码镜头位置定位菜单
  let mouseX = 0,
    mouseY = 0;

  if (window.lastMouseEvent) {
    mouseX = window.lastMouseEvent.clientX;
    mouseY = window.lastMouseEvent.clientY;
  } else {
    const editorDom = editor.getDomNode();
    const editorRect = editorDom.getBoundingClientRect();
    const lineHeight = editor.getOption(monaco.editor.EditorOption.lineHeight);

    mouseX = editorRect.left + 50;
    mouseY =
      editorRect.top +
      (range.startLineNumber - editor.getVisibleRanges()[0].startLineNumber) *
        lineHeight;
  }

  menuDiv.style.left = mouseX + "px";
  menuDiv.style.top = mouseY + "px";
  document.body.appendChild(menuDiv);

  // 调整位置以保持在视口内
  const menuRect = menuDiv.getBoundingClientRect();
  const viewportWidth = window.innerWidth;
  const viewportHeight = window.innerHeight;

  if (menuRect.right > viewportWidth) {
    menuDiv.style.left = mouseX - menuRect.width + "px";
  }

  if (menuRect.bottom > viewportHeight) {
    menuDiv.style.top = mouseY - menuRect.height + "px";
  }

  // 创建菜单项
  options.forEach((option) => {
    const itemDiv = document.createElement("div");
    itemDiv.className = "chat-jpt-code-menu-item";
    itemDiv.textContent = option.label;
    itemDiv.style.cssText = `
      padding: 6px 12px;
      cursor: pointer;
      color: #ddd;
      white-space: nowrap;
    `;

    itemDiv.addEventListener("mouseover", () => {
      itemDiv.style.backgroundColor = "#3e3e3e";
    });

    itemDiv.addEventListener("mouseout", () => {
      itemDiv.style.backgroundColor = "transparent";
    });

    itemDiv.addEventListener("click", () => {
      // 移除菜单
      try {
        if (document.body.contains(menuDiv)) {
          document.body.removeChild(menuDiv);
        }
        document.removeEventListener("click", closeMenu);
      } catch (error) {
        console.log("选项点击移除菜单失败:", error);
      }

      // 处理复制代码选项
      if (option.type === "copy") {
        try {
          navigator.clipboard.writeText(codeContent).then(() => {
            showNotification("代码已复制到剪贴板");
          });
        } catch (error) {
          console.error("复制代码失败:", error);
        }
        return;
      }

      // 发送到AI进行分析
      chatRunner(option.type);

      // 高亮选定的代码
      editor.revealRangeInCenter(range);
    });

    menuDiv.appendChild(itemDiv);
  });

  // 添加关闭按钮
  const closeButton = document.createElement("div");
  closeButton.className = "chat-jpt-code-menu-close";
  closeButton.textContent = "取消";
  closeButton.style.cssText = `
    padding: 6px 12px;
    cursor: pointer;
    color: #888;
    border-top: 1px solid #444;
    text-align: center;
    margin-top: 4px;
  `;

  closeButton.addEventListener("mouseover", () => {
    closeButton.style.backgroundColor = "#3e3e3e";
  });

  closeButton.addEventListener("mouseout", () => {
    closeButton.style.backgroundColor = "transparent";
  });

  closeButton.addEventListener("click", () => {
    try {
      if (document.body.contains(menuDiv)) {
        document.body.removeChild(menuDiv);
      }
      document.removeEventListener("click", closeMenu);
    } catch (error) {
      console.log("关闭按钮移除菜单失败:", error);
    }
  });

  menuDiv.appendChild(closeButton);

  // 点击外部时关闭菜单
  const closeMenu = (e) => {
    if (!menuDiv.contains(e.target)) {
      try {
        if (document.body.contains(menuDiv)) {
          document.body.removeChild(menuDiv);
        }
      } catch (error) {
        console.log("移除菜单节点失败:", error);
      } finally {
        document.removeEventListener("click", closeMenu);
      }
    }
  };

  setTimeout(() => {
    document.addEventListener("click", closeMenu);
  }, 100);
}

/**
 * Gets document symbols using regex for function and class detection
 * @param {Object} model - The Monaco editor model
 * @param {Object} monaco - The Monaco instance
 * @returns {Promise<Array>} - Promise resolving to an array of document symbols
 * @private
 */
function getDocumentSymbols(model, monaco) {
  return new Promise((resolve) => {
    try {
      const result = findFunctionsByRegex(model);
      resolve(result);
    } catch (error) {
      console.error("获取文档符号失败:", error);
      resolve([]);
    }
  });
}

/**
 * Finds functions, classes and methods using regex
 * @param {Object} model - The Monaco editor model
 * @returns {Array} - Array of document symbols
 * @private
 */
function findFunctionsByRegex(model) {
  const text = model.getValue();
  const result = [];

  // Match different function declarations
  const patterns = [
    {
      regex: /function\s+(\w+)\s*\([^)]*\)\s*{/g,
      kind: "Function",
    },
    {
      regex: /(?:const|let|var)\s+(\w+)\s*=\s*function\s*\([^)]*\)\s*{/g,
      kind: "Function",
    },
    {
      regex: /(?:const|let|var)\s+(\w+)\s*=\s*\([^)]*\)\s*=>\s*{/g,
      kind: "Function",
    },
    {
      regex: /class\s+(\w+)(?:\s+extends\s+\w+)?\s*{/g,
      kind: "Class",
    },
  ];

  patterns.forEach((pattern) => {
    let match;
    while ((match = pattern.regex.exec(text)) !== null) {
      const name = match[1] || match[0].trim();
      const startPos = model.getPositionAt(match.index);

      // Find function body end position
      let endPos;
      if (match[0].includes("{")) {
        let openBraces = 1;
        let searchStartPos = match.index + match[0].length;

        for (let i = searchStartPos; i < text.length; i++) {
          if (text[i] === "{") openBraces++;
          else if (text[i] === "}") openBraces--;

          if (openBraces === 0) {
            endPos = model.getPositionAt(i + 1);
            break;
          }
        }
      }

      if (!endPos) {
        endPos = {
          lineNumber: startPos.lineNumber,
          column: model.getLineMaxColumn(startPos.lineNumber),
        };
      }

      result.push({
        name: name,
        kind: pattern.kind,
        range: {
          startLineNumber: startPos.lineNumber,
          startColumn: startPos.column,
          endLineNumber: endPos.lineNumber,
          endColumn: endPos.column,
        },
        children: [],
      });
    }
  });

  return result;
}
